package mpbe.estructura.secciones.hormigon_armado;

/*
 * Este codigo es software libre y se encuentra licenciado 
 * bajo los términos de la Licencia Pública General de GNU versión 3 
 * según se encuentra publicada por la Free Software Foundation.
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Autor: Martin Pablo Bellanca <martin.bellanca@gmail.com>
 * web: http://mpbe.blogspot.com/
 */

import java.util.Iterator;
import java.util.Vector;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import mpbe.estructura.secciones.hormigon_armado.contornos.SHContorno;
import mpbe.geometria.Limites;
import mpbe.geometria.Punto;

public class SHContornos {
	private Vector<SHContorno> contornos;
	private double intervaloCalculo;
	private boolean guardar;
	private boolean recalcular;
	
	
	//-------------------------------------
	// Constructores
	//-------------------------------------
	public SHContornos() {
		contornos = new Vector<SHContorno>();
		contornos.add(new SHContorno(true, "Contorno"));
		intervaloCalculo = 0.0005;
		guardar = true;
		recalcular = true;
	}
	
	
	//-------------------------------------
	// Funciones de la seccion
	//-------------------------------------
	public Limites getLimitesV() {
		Limites LM = new Limites();
		LM.max = 0;
		LM.min = 0;
		Punto PPP = new Punto();
		SHContorno CCC= new SHContorno();
		int c= 0; 
		do {
			if (c==contornos.size()) return LM;
			CCC = contornos.get(c);
			c++;
		} while (!CCC.activo);
		Iterator IIP=CCC.nodos.iterator();
		while (IIP.hasNext()) {
			PPP=(Punto)IIP.next();
			if (PPP.Y<LM.min) LM.min = PPP.getY();
			if (PPP.Y>LM.max) LM.max = PPP.getY();
		}
		return LM;
	}
	
	public Limites getLimitesH() {
		Limites LM = new Limites();
		LM.max = 0;
		LM.min = 0;
		Punto PPP = new Punto();
		SHContorno CCC= new SHContorno();
		int c= 0; 
		do {
			if (c==contornos.size()) return LM;
			CCC = contornos.get(c);
			c++;
		} while (!CCC.activo);
		Iterator IIP=CCC.nodos.iterator();
		while (IIP.hasNext()) {
			PPP=(Punto)IIP.next();
			if (PPP.X<LM.min) LM.min = PPP.X;
			if (PPP.X>LM.max) LM.max = PPP.X;
		}
		return LM;
	}
	
	
	//------------------------------------
	// Funciones de Intervalo de Calculo
	//------------------------------------	
	/**
	 * @param Valor
	 * @uml.property  name="intervaloCalculo"
	 */
	public void setIntervaloCalculo(double Valor) {intervaloCalculo=Valor;}
	/**
	 * @return
	 * @uml.property  name="intervaloCalculo"
	 */
	public double getIntervaloCalculo() {return intervaloCalculo;}
	public void ajustarIntervaloA(int Presicion_en_Decimales) {
		double Area=getArea();
		double AreaAprox=0;
		FuncionA FA=null;
		intervaloCalculo=1;
		while (Math.pow(Math.abs(Area-AreaAprox),Presicion_en_Decimales)>Presicion_en_Decimales) {
			intervaloCalculo/=2;
			AreaAprox=areaIntegrada(FA, false, 0, false, 0);
		}
	}
	
	
	//-------------------------------------
	// Propiedades de la seccion
	//-------------------------------------
	public double getArea() {
		
		// Definicion de Variables generales
		double Area=0, AreaContorno=0;
		Iterator<SHContorno> IIC;		
		SHContorno CCC;
		Punto P1 = new Punto();
		Punto P2 = new Punto();

		IIC=contornos.iterator();
		while (IIC.hasNext()) {
			CCC = new SHContorno();
			((SHContorno) IIC.next()).copyInto(CCC);
			//CCC.mover(0, deltaY);
			AreaContorno=0;
			if (CCC.activo) {	
				if (CCC.nodos.size()>=3) {
				      //producto en cruz desde 1 hasta n-1
				      for(int i=0;i<CCC.nodos.size();i++) {
				    	  P1=CCC.nodos.get(i);
				    	  if (i != (CCC.nodos.size()-1))
				    		  P2=CCC.nodos.get(i+1);
				    	  else
				    		  P2=CCC.nodos.get(0);
				    	  AreaContorno+=P1.X*P2.Y-
				              P1.Y*P2.X;
				        }//for
				    }//if
				AreaContorno = Math.abs(AreaContorno) / 2;
			}
			if (Area==0) Area=AreaContorno; else Area-=AreaContorno;
		}
		return Area;
	}
	
	public double areaIntegrada(Funcion_Area Funcion, boolean UsarSup, double LimiteSup, boolean UsarInf, double LimiteInf) {
		// TODO no integra huecos?
		
		//Definicion de Variables generales
		double Area=0;
		Iterator<SHContorno> IIC;
		Punto PPP = new Punto(), PPP1= new Punto();
		
		// Verifica si se puede calcular el area
		int CanContornos= contornos.size();
		if ((CanContornos<1)||(intervaloCalculo<=0)) return Area; //Hay contornos y el intervalo es mayor de o
		SHContorno CCC= contornos.get(0); //***********comienza en 0
		if (CCC.nodos.size()<3) return Area;
		Punto P1=CCC.nodos.get(0); 
		Punto P2=CCC.nodos.get(1);
		Punto P3=CCC.nodos.get(2);
		if ((P1.Y==P2.Y)&&(P2.Y==P3.Y)) return Area;
		
		// Obtiene Ymax y Ymin
		//calc_Extremos();
		Limites lim = getLimitesV();
		double Ymax=lim.max, Ymin=lim.min;
		
		// Defini los limites del calculo
		if ((UsarSup==true)&&(LimiteSup<Ymax)) Ymax=LimiteSup;
		if ((UsarInf==true)&&(LimiteInf>Ymin)) Ymin=LimiteInf;
		
		// Calcula el intervalo de calculo
		int CanInter= (int) ((Ymax-Ymin)/intervaloCalculo+1);
		double Inter=(Ymax-Ymin)/CanInter;
		if (Inter==0) return Area;
		
		//Calcula area
		int CanP, CanTP=0;
		double XX[]= new double[20];
		double Dx, Dy, Dyy;
		double LongFranja=0;
		IIC=contornos.iterator();
		//System.out.println("Ymax ="+(Ymax+Inter/2.0));
		//System.out.println("Ymin ="+(Ymin-Inter/2));
		for (double YY=Ymax-Inter/2.0; YY>Ymin; YY-=Inter) {
			//System.out.println("YY ="+YY);
			// localiza los puntos XX()
			CanP = 0;
			IIC=contornos.iterator();
			while (IIC.hasNext()) { //recorre los contornos
				CCC=(SHContorno)IIC.next();
				if (CCC.activo == true) {
					CanTP=CCC.nodos.size();
					for (int PP=0; PP<CanTP; PP++) {
						PPP=CCC.nodos.get(PP);
						if (PP==(CanTP-1))
							PPP1=CCC.nodos.get(0);
						else 
							PPP1=CCC.nodos.get(PP+1);
						//System.out.println("P ="+PPP.X+","+PPP.Y);
						//System.out.println("P1 ="+PPP1.X+","+PPP1.Y);
						if (((PPP.Y>YY)&&(PPP1.Y<YY))||((PPP.Y<YY)&&(PPP1.Y>YY))) {
							CanP++;
							Dx=PPP1.X-PPP.X;
							Dy=PPP1.Y-PPP.Y;
							//Dyy=PPP.Y-YY;
							if (Dx!=0) {
								double tg = Dy/Dx;
								double h = PPP.Y-tg*PPP.X;
								XX[CanP]=(YY-h)/tg;
							} else XX[CanP]=PPP.X;
							//XX[CanP]=PPP.X+Dx*Dyy/Dy;
							// Y = tg alfa*X+H
							//System.out.println("Valor de borde"+XX[CanP]);
						}
					}
				}
			} 
			// Ordena los puntos
			do {
				Dy=0;
				for (int NN=2; NN<=CanP; NN++) {
					if (XX[NN]<XX[NN-1]) {
						Dx=XX[NN-1];
						XX[NN-1]=XX[NN];
						XX[NN]=Dx;
						Dy++;
					}
				}
			} while (Dy!=0);
			
			// Calcula el area de la franja
			LongFranja=0;
			for (int NN=2; NN<=CanP; NN+=2) {
				LongFranja+=XX[NN]-XX[NN-1];
				//System.out.println("Puntos="+XX[NN]+" / "+XX[NN-1]);
			}
			//System.out.println("Puntos="+XX[1]+" / "+XX[2]);
			//System.out.println("pos="+YY+"  -  Long Franja="+LongFranja);
			Area+=LongFranja*Inter*Funcion.Ejecutar(YY, LongFranja, Inter)+Funcion.sum;
		}
		return Area;
	}
	
	public double getAreaIntegrada() {
		FuncionA FA = new FuncionA();
		return areaIntegrada(FA, false, 0, false, 0);
	}
	
	public double getInercia() {
		FuncionI FI = new FuncionI();
		return areaIntegrada(FI, false, 0, false, 0);
	}

	public double getMtoEstatico() {
		FuncionME FM= new FuncionME();
		return areaIntegrada(FM, false, 0, false, 0);
	}	
	
	public Vector<Double> getInterseccionPlano(double YY){
		Iterator IIC;
		Punto PPP = new Punto(), PPP1= new Punto();
		int CanTP=0;
		Vector<Double> XX= new Vector<Double>(2);
		double Dx, Dy, Dyy;
		double LongFranja=0;
		SHContorno CCC= contornos.get(0); //***********comienza en 0
		IIC=contornos.iterator();
		while (IIC.hasNext()) { //recorre los contornos
			CCC=(SHContorno)IIC.next();
			CanTP=CCC.nodos.size();
			for (int PP=0; PP<CanTP; PP++) {
				PPP=CCC.nodos.get(PP);
				if (PP==(CanTP-1))
					PPP1=CCC.nodos.get(0);
				else 
					PPP1=CCC.nodos.get(PP+1);
				//System.out.println("P ="+PPP.X+","+PPP.Y);
				//System.out.println("P1 ="+PPP1.X+","+PPP1.Y);
				if (((PPP.Y>YY)&&(PPP1.Y<YY))||((PPP.Y<YY)&&(PPP1.Y>YY))) {
					Dx=PPP.X-PPP1.X;
					Dy=PPP.Y-PPP1.Y;
					Dyy=PPP.Y-YY;
					XX.add(PPP.X+Dx*Dyy/Dy);
					//System.out.println("Valor de borde"+XX[CanP]);
				}
			}
		} 
		// Ordena los puntos
		do {
			Dy=0;
			for (int NN=1; NN<XX.size(); NN++) {
				if (XX.get(NN)<XX.get(NN-1)) {
					Dx=XX.get(NN-1);
					XX.set(NN-1, XX.get(NN));
					XX.set(NN, Dx);
					Dy++;
				}
			}
		} while (Dy!=0);
		
		return XX;
		
	}
	
	
	//-------------------------------------
	// delegados de Guargar y recalcular
	//-------------------------------------
	public boolean isGuardar() {
		return guardar;
	}

	public void setGuardar(boolean guardar) {
		this.guardar = guardar;
	}

	public boolean isRecalcular() {
		return recalcular;
	}

	public void setRecalcular(boolean recalcular) {
		this.recalcular = recalcular;
	}

	
	//**********************************
	// Funciones de modificacion
	//**********************************
	public void mod_InvertirV(){
		// invierte contornos
		if (contornos!=null) {
			SHContorno contorno;
			for (int cc=0; cc<contornos.size(); cc++){
				contorno = contornos.get(cc);
				contorno.mod_InvertirV();
			}
		}
	}
	
	public void mover(double deltaX, double deltaY) {
		SHContorno contorno;
		for (int cc=0; cc<contornos.size(); cc++){
			contorno = contornos.get(cc);
			contorno.mover(deltaX, deltaY);
		}
	}
	
	public void rotar(double grados){
		double rad, l;
		double delta = grados*Math.PI/180;
		// Contornos
		SHContorno contorno;
		for (int cc=0; cc<contornos.size(); cc++){
			contorno = contornos.get(cc);
			contorno.rotar(grados);
		}
	}
		
	
	//*****************************************************
	// Funciones JSON
	//*****************************************************
	public void put_JSON(JSONArray ja){
		JSONObject joa = new JSONObject();	
		contornos.clear();
		SHContorno co;
		for (int ii=0; ii<ja.size(); ii++) {
			joa = (JSONObject) ja.get(ii);
			co = new SHContorno();
			co.put_JSON(joa);
			contornos.add(co);
		}
	}
	public JSONArray get_JSONArray() {		
		JSONArray ja = new JSONArray();
		SHContorno co = new SHContorno();
		for (int ii=0; ii<contornos.size(); ii++) {
			co = contornos.get(ii);
			ja.add(co.get_JSONObject());	
		}
		return ja;
	}
	public String get_JSONString(int tab) {
		String res = tabs(tab+1)+"[\n";
		SHContorno co = new SHContorno();
		for (int ii=0; ii<contornos.size(); ii++) {
			co = contornos.get(ii);
			res += co.get_JSONString(tab+2);
			if (ii==contornos.size()-1) res += "\n"+tabs(tab+1)+"],\n"; else res += ",\n";
		}
		return res;
	}
	
	private String tabs(int can) {
		String str = new String();
		for (int ii=0; ii<can; ii++) str += "   "; // \t
		return str;
	}
	
	
	//-------------------------------------
	// delegados de Contorno
	//-------------------------------------
	public void add(int index, SHContorno element) {
		contornos.add(index, element);
		guardar = true;
		recalcular = true;
	}

	public boolean add(SHContorno e) {
		guardar = true;
		recalcular = true;
		return contornos.add(e);
	}

	public int capacity() {
		return contornos.capacity();
	}

	public void clear() {
		contornos.clear();
		guardar = true;
		recalcular = true;
	}

	public Object clone() {
		return contornos.clone();
	}

	public void copyInto(Vector <SHContorno> contornos)
	{	
		contornos.clear();
		Iterator<SHContorno> it = this.contornos.iterator();
		SHContorno cc;
		while (it.hasNext()) {
			cc = new SHContorno();
			it.next().copyInto(cc);
			contornos.add(cc);
		} ;
		
	}
	
	public SHContorno firstElement() {
		return contornos.firstElement();
	}

	public SHContorno get(int index) {
		return contornos.get(index);
	}
	
	/**
	 * @return
	 * @uml.property  name="contornos"
	 */
	public Vector<SHContorno> getContornos() {
		return contornos;
	}
	
	/**
	 * @param contornos
	 * @uml.property  name="contornos"
	 */
	public void setContornos(Vector<SHContorno> contornos) {
		this.contornos = contornos;
	}

	public int indexOf(Object o, int index) {
		return contornos.indexOf(o, index);
	}

	public int indexOf(Object o) {
		return contornos.indexOf(o);
	}

	public boolean isEmpty() {
		return contornos.isEmpty();
	}

	public Iterator<SHContorno> iterator() {
		return contornos.iterator();
	}

	public SHContorno lastElement() {
		return contornos.lastElement();
	}

	public int lastIndexOf(Object o, int index) {
		return contornos.lastIndexOf(o, index);
	}

	public int lastIndexOf(Object o) {
		return contornos.lastIndexOf(o);
	}

	public SHContorno remove(int index) {
		guardar = true;
		recalcular = true;
		return contornos.remove(index);
	}

	public boolean remove(Object o) {
		guardar = true;
		recalcular = true;
		return contornos.remove(o);
	}

	public SHContorno set(int index, SHContorno element) {
		guardar = true;
		recalcular = true;
		return contornos.set(index, element);
	}

	public void setSize(int newSize) {
		contornos.setSize(newSize);
	}

	public int size() {
		return contornos.size();
	}

	public String toString() {
		return contornos.toString();
	}

}


//------------------------------------
//Funciones de Area
//------------------------------------
class FuncionA implements Funcion_Area {
	public double Ejecutar(double Y, double LongFranja, double Inter) {return 1.0;}
}

class FuncionME implements Funcion_Area {
	public double sum = 0;
	public double Ejecutar(double Y, double LongFranja, double Inter) {
		return Y;
	}
}

class FuncionI implements Funcion_Area {
	public double sum = 0;
	public double Ejecutar(double Y, double LongFranja, double Inter) {
		sum = LongFranja*Inter*Inter*Inter/12;
		return Y*Y;}
}

/**
* @author  mpbe
*/
class FuncionDbu implements Funcion_Area {
	// Variables de trabajo
	public double Ymax = 0;
	public double Ymin = 0;
	/**
	 * @uml.property  name="rU"
	 * @uml.associationEnd  
	 */
	public RectaUltima RU = new RectaUltima();
	public double Br = 0;
	//private double Area=0;
	private double E=0;
	private double Dbu1=0;
	
	// Variables de resultado
	public double sum = 0;
	public double Dbu = 0;
	public double Mto = 0;
	public double Ese = 0;
	
	public double Ejecutar(double Y, double LongFranja, double Inter) {
		//Area+=LongFranja*Inter;
		//E=RU.Eb1*(1-(Y-Ymin)/RU.X);
		E = Math.abs(RU.Eb1*(Y-(Ymax-RU.X))/RU.X);
		Ese = Math.abs(Ese);
		if (Math.abs(E)<Ese) 
			Dbu1= -Br*(E-E*E/Ese/Ese)*LongFranja*Inter;
		else 
			Dbu1= -Br*LongFranja*Inter;
		Dbu+=Dbu1;
		Mto+=Dbu1*Y;
		return 0;
	}
	
}